iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0

上一篇我們有提到用 KAPT 參數去呼叫 純 Kotlin 和 Android 的 code generator ,這篇要延續這個主題,繼續來講一下會怎麼樣去呼叫它們來產生程式碼。

我們在 annotation processor 裡面有定義了 process 的方法:

@SupportedOptions("debug")
@AutoService(Processor::class)
class RssAnnotationProcessor : AbstractProcessor() {
	// 略
	override fun process(typeElementSet: MutableSet<out TypeElement>?, roundEnvironment: RoundEnvironment?): Boolean {
      val logger = Logger(processingEnv.messager)
      val isPureKotlinParser = processingEnv.options[KAPT_OPTION_KEY]?.toBoolean() ?: false
      if (isPureKotlinParser) {
          generateClassesForKotlin(logger, roundEnvironment)
      } else {
          generateClassesForAndroid(logger, roundEnvironment)
      }
      return true
  }
	// 略
}

其中的 generateClassesForKotlin 是產生 Kotlin 的 extension 和 parser 的地方。

private fun generateClassesForKotlin(logger: Logger, roundEnvironment: RoundEnvironment?) {
    if (!isExtensionGenerated) {
        KotlinExtensionGenerator(logger).generate().writeTo(processingEnv.filer)
        isExtensionGenerated = true
    }

    generateParsers(roundEnvironment) { isRoot, element ->
        logger.log("[RssAnnotationProcessor][generateClassesForKotlin] isRoot = $isRoot, element = $element")
        KotlinParserGenerator(
            element = element,
            isRoot = isRoot,
            logger = logger
        ).generate().writeTo(processingEnv.filer)
    }
}

generateClassesForAndroid 則是負責產生 Android 的 extension 和 parser 。

private fun generateClassesForAndroid(logger: Logger, roundEnvironment: RoundEnvironment?) {
    // This 'process' method could be called multiple times, so we use a flag to prevent it generate multiple times.
    if (!isExtensionGenerated) {
        AndroidExtensionGenerator(logger).generate().writeTo(processingEnv.filer)
        isExtensionGenerated = true
    }
    generateParsers(roundEnvironment) { isRoot, element ->
        AndroidParserGenerator(
            element = element,
            isRoot = isRoot,
            logger = logger
        ).generate().writeTo(processingEnv.filer)

        if (isRoot) {
            AndroidReaderParserGenerator(
                rootClassName = element.simpleName.toString(),
                rootClassPackage = element.getPackage(),
                logger
            ).generate().writeTo(processingEnv.filer)
        }
    }
}

因為 process 方法在 annotation processor 裡面會被呼叫多次,每當有類別的 annotation 被掃到,就會被呼叫一次,每次都是不同的 generation cycle ,被產生的 class 也會被放在不同的檔案裏面。

Android 的部分比較特殊的地方是它有產生自己的 reader ,它跟 parser 的不同在於它是使用產生後的 parser 去做其他的處理,像是資料快取和取得網路的 RSS 檔案來源,等於是把 parser 再包一層好用的 API ,這樣在 Android 上面可以更簡單地被使用。資料快取的部分,android 會用 database 以 url 當成是 key 去把資料存起來,也有設置過期時間,這樣可以確保不會抓到過期的資訊,也讓快取可以發揮作用。當然,外部 API 還是要按照自己的需求設計,也可以設計成讓使用者可以決定要不要使用快取。在取得網路 RSS 來源的部分,是使用了 OkHttp 直接去取得檔案內容。這些 Kotlin 和 Android 的 generator 會在後面的文章一一為各位講解。


上一篇
Code Generator 結構
下一篇
Logger 與 Extension Generator for Kotlin
系列文
如何使用 Kotlin Annotation Processor 做出自己的 Custom Data Parser Library30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言